export function parseQueryString(queryString: string) {
	const obj = {} as any
	const reg = /([^?&=]+)=([^?&=]*)/g
	queryString.replace(reg, (rs, $1, $2) => {
		const name = decodeURIComponent($1)
		obj[name] = decodeURIComponent($2)
		return rs
	})
	return obj
}

/**
 * Get query string, parses and decodes it.
 */
export function parseUrlString(url: string) {
	return parseQueryString(getQuery(url))
}

/**
 * Encode object into a query string.
 */
export function encodeQueryString(obj: any): string {
	const query: string[] = []
	let arrValues, reg
	for (const key in obj) {
		if (obj.hasOwnProperty(key)) {
			const val = obj[key]
			if (Array.isArray(val)) {
				arrValues = key + '='
				reg = new RegExp('&' + key + '+=$')
				for (const i in val) {
					arrValues += encodeURIComponent(val[i]) + '&' + key + '='
				}
				query.push(arrValues.replace(reg, ''))
			} else {
				query.push(key + '=' + encodeURIComponent(val))
			}
		}
	}
	return query.join('&')
}

/**
 * Gets full query as string with all special chars decoded.
 */
export function getQuery(url: string): string {
	url = url.replace(/#.*/, '') // removes hash (to avoid getting hash query)
	const queryString = /\?[a-zA-Z\d=&%$\-_.+!*'(),\[\]{}:]+/.exec(url) // valid chars according to: http://www.ietf.org/rfc/rfc1738.txt
	return queryString ? decodeURIComponent(queryString[0]) : ''
}

/**
 * Checks if query string contains parameter.
 */
export function containParameter(url: string, paramName: string): boolean {
	const regex = new RegExp('(\\?|&)' + paramName + '=', 'g') // matches `?param=` or `&param=`
	return regex.test(getQuery(url))
}

/**
 * Decode query string into an object of keys => vals.
 */
export function decodeQueryString(queryStr: string): any {
	const queryArr = (queryStr || '').replace('?', '').split('&')
	const length = queryArr.length
	const obj = {} as any
	let count = -1
	let item, pValue, pName, toSet
	while (++count < length) {
		item = queryArr[count].split('=')
		pName = item[0]
		if (!pName || !pName.length) {
			continue
		}
		if (pName.endsWith('[]')) {
			pName = pName.substr(0, pName.length - 2)
		}
		pValue = item[1]
		toSet = typeof pValue === 'string' ? decodeURIComponent(pValue) : pValue
		if (obj.hasOwnProperty(pName)) {
			const val = obj[pName]
			if (Array.isArray(val)) {
				obj[pName].push(toSet)
			} else {
				obj[pName] = [val, toSet]
			}
		} else {
			obj[pName] = toSet
		}
	}
	return obj
}

/**
 * Get query parameter value.
 */
export function getParamValue(url: string, param: string) {
	const regexp = new RegExp('(\\?|&)' + param + '=([^&]*)') // matches `?param=value` or `&param=value`, value = $2
	const result = regexp.exec(getQuery(url))
	return (result && result[2]) ? result[2] : null
}

/**
 * Set query string parameter value
 */
export function setParamValue(url: string, paramName: string, value: string) {
	url = url || ''

	const re = new RegExp('(\\?|&)' + paramName + '=[^&]*')
	const param = paramName + '=' + encodeURIComponent(value)

	if (re.test(url)) {
		return url.replace(re, '$1' + param)
	} else {
		if (url.indexOf('?') === -1) {
			url += '?'
		}
		if (url.indexOf('=') !== -1) {
			url += '&'
		}
		return url + param
	}
}

export function isSameQuery(a: any, b: any) {
	if (a == null) return true
	else if (b == null) return false
	else { // a != null && b != null
		for (const key in a) {
			if (a.hasOwnProperty(key) && a[key] != b[key]) {
				return false
			}
		}
	}
	return true
}
